# +----------------------------------------------------------------------
# | ChatWork
# +----------------------------------------------------------------------
# | 这不是一个自由软件,您只能在不用于商业目的的前提下对程序代码进行修改和使用。
# | 任何企业和个人不允许对程序代码以任何形式任何目的再发布,商业使用请获取授权。
# +----------------------------------------------------------------------
# | Author: ChatWork Team <2474369941@qq.com>
# +----------------------------------------------------------------------
import time
from typing import List
from tortoise.transactions import in_transaction
from exception import AppException
from common.utils.urls import UrlUtil
from common.utils.config import ConfigUtil
from common.models.agents import AgentRobotModel
from common.models.agents import AgentChatRecordsModel
from common.models.agents import AgentChatSessionModel
from common.models.agents import AgentChatRoomingModel
from common.models.agents import AgentRobotCollectModel
from common.models.agents import AgentRobotInstructModel
from apps.api.schemas.agent.chat import rooming_schema as schema


class ChatRoomingService:
    """ 对话窗口服务类 """

    @classmethod
    async def lists(cls, user_id: int) -> List[schema.ChatRoomingListVo]:
        """
        对话窗口列表

        Args:
            user_id (int): 用户ID

        Returns:
            List[schema.ChatRoomingListVo]

        Author:
            zero
        """
        rooming = await AgentChatRoomingModel.filter(user_id=user_id, is_delete=0).order_by("-id").all()

        robot_ids = [item.robot_id for item in rooming if item.robot_id] or [0]
        robots = await (AgentRobotModel
                        .filter(id__in=robot_ids)
                        .all().values(*("id,code,logo,name,intro".split(","))))

        lists = []
        for robot in robots:
            robot["logo"] = await UrlUtil.to_absolute_url(robot["logo"])
            lists.append(schema.ChatRoomingListVo(
                code=robot["code"],
                logo=robot["logo"],
                name=robot["name"],
                intro=robot["intro"]
            ))

        return lists

    @classmethod
    async def init(cls, user_id: int, bot: str) -> schema.ChatRoomingInitVo:
        """
        对话窗口初始

        Args:
            user_id (int): 用户ID
            bot (str): 智能体编号

        Returns:
            schema.ChatRoomingInitVo

        Author:
            zero
        """
        robot = await AgentRobotModel.filter(code=bot).first()
        if not robot:
            raise AppException("智能体已不存在")

        # 收藏数量
        collect_num = await (AgentRobotCollectModel
                             .filter(robot_id=robot.id)
                             .filter(is_delete=0)
                             .count())

        # 是否收藏
        is_collect = await (AgentRobotCollectModel
                            .filter(user_id=user_id)
                            .filter(robot_id=robot.id)
                            .filter(is_delete=0)
                            .first())

        # 联网搜索
        is_web_search: bool = bool(await ConfigUtil.get("web_search", "status", 0))

        # 内置指令
        instruct = []
        directs = await AgentRobotInstructModel.filter(robot_id=robot.id, scene="direct").order_by("-sort").all()
        for direct in directs:
            instruct.append({"name": direct.keyword, "content": direct.content})

        # 返回结果
        return schema.ChatRoomingInitVo(
            code=robot.code,
            logo=await UrlUtil.to_absolute_url(robot.logo),
            name=robot.name,
            intro=robot.intro,
            welcome_text=robot.welcome_text,
            collect_num=collect_num,
            is_collect=True if is_collect else False,
            is_web_search=is_web_search,
            max_upload_num=robot.max_upload_num,
            is_upload_files=robot.is_upload_files,
            is_upload_image=robot.is_upload_image,
            is_show_timed=robot.is_show_timed,
            is_show_quote=robot.is_show_quote,
            is_show_context=robot.is_show_context,
            instruct=instruct
        )

    @classmethod
    async def create(cls, bot: str, user_id: int):
        """
        对话窗口创建

        Args:
            bot (str): 智能体编号
            user_id (int): 用户ID

        Author:
            zero
        """
        robot = await AgentRobotModel.filter(code=bot, is_delete=0).first()
        if not robot:
            raise AppException("智能体不存在")

        rooming = await AgentChatRoomingModel.filter(robot_id=robot.id, user_id=user_id, is_delete=0).first()
        if not rooming:
            await AgentChatRoomingModel.create(
                bot=robot.code,
                user_id=user_id,
                robot_id=robot.id,
                create_time=int(time.time()),
                update_time=int(time.time())
            )

    @classmethod
    async def delete(cls, bot: str, user_id: int):
        """
        对话窗口删除

        Args:
            bot (str): 智能体编号
            user_id (int): 用户ID

        Author:
            zero
        """
        # 查询房间
        rooming = await (AgentChatRoomingModel
                         .filter(bot=bot)
                         .filter(user_id=user_id)
                         .filter(is_delete=0)
                         .get())

        async with in_transaction("mysql"):
            # 删除房间
            await (AgentChatRoomingModel
                   .filter(id=rooming.id)
                   .update(
                        is_delete=1,
                        delete_time=int(time.time())
                   ))

            # 删除记录
            sessions = await AgentChatSessionModel.filter(room_id=rooming.id, is_delete=0).values("id")
            session_ids = [item["id"] for item in sessions]
            if session_ids:
                await AgentChatSessionModel.filter(id__in=session_ids).update(
                    is_delete=1,
                    delete_time=int(time.time())
                )

                await (AgentChatRecordsModel
                       .filter(robot_id=rooming.robot_id)
                       .filter(session_id__in=session_ids)
                       .filter(user_delete=0)
                       .update(
                            is_delete=1,
                            delete_time=int(time.time())
                       ))
